package com.cangsan.erhai.service.impl;

import cn.hutool.Hutool;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.cangsan.erhai.common.R;
import com.cangsan.erhai.config.WechatConfig;
import com.cangsan.erhai.entity.CreateOrderReq;
import com.cangsan.erhai.entity.SysUser;
import com.cangsan.erhai.entity.TabOrder;
import com.cangsan.erhai.entity.TabVipGoods;
import com.cangsan.erhai.mapper.SysUserMapper;
import com.cangsan.erhai.mapper.TabOrderMapper;
import com.cangsan.erhai.mapper.TabVipGoodsMapper;
import com.cangsan.erhai.security.WechatAuthenticationToken;
import com.cangsan.erhai.util.SecurityUtil;
import com.cangsan.erhai.vo.QueryOrderReq;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;

import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;

import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

@Slf4j
@Service
public class WechatPayService {
    @Autowired
    private WechatConfig wechatConfig;
//    @Autowired
    private RSAAutoCertificateConfig rsaAutoCertificateConfig=null;
    @Autowired
    private TabOrderMapper tabOrderMapper;
    @Autowired
    private TabVipGoodsMapper tabVipGoodsMapper;
    @Autowired
    private SysUserMapper sysUserMapper;


    /**
     * 创建微信预支付订单
     * @param req
     * @return
     * @throws Exception
     */
    public R createOrder(CreateOrderReq req) throws Exception{
        TabOrder tabOrder = creatLocalOrder(req);
        //创建微信预支付订单
        JsapiServiceExtension preOrderService =
                new JsapiServiceExtension.Builder()
                .config(rsaAutoCertificateConfig)
                .build();
        //预支付订单返回,小程序支付的响应
        PrepayWithRequestPaymentResponse response=
                new PrepayWithRequestPaymentResponse();
        PrepayRequest request = new PrepayRequest();
        request.setAppid(wechatConfig.getAppid());
        request.setMchid(wechatConfig.getMerchantId());
        request.setDescription(tabOrder.getDescription());
        request.setOutTradeNo(tabOrder.getOutTradeNo());
        request.setNotifyUrl(wechatConfig.getPayNotifyUrl());
        Amount amount = new Amount();
        amount.setTotal(tabOrder.getTotalFee());
        request.setAmount(amount);
        Payer payer = new Payer();
        payer.setOpenid(tabOrder.getOpenId());
        request.setPayer(payer);
        response= preOrderService.prepayWithRequestPayment(request);
        tabOrderMapper.insert(tabOrder);
        return R.ok(response);

    }

    private TabOrder creatLocalOrder(CreateOrderReq req){
        SysUser user = sysUserMapper.selectById(req.getUserId());
        TabVipGoods tabVipGoods = tabVipGoodsMapper.selectById(req.getVipGoodsId());
        TabOrder tabOrder = new TabOrder();
        tabOrder.setPayStatus(0);
        tabOrder.setDescription(tabVipGoods.getDescription());
        tabOrder.setOpenId(user.getOpenId());
        tabOrder.setNickName(user.getNickName());
        tabOrder.setPhonenumber(user.getPhonenumber());
        tabOrder.setTotalFee(tabVipGoods.getTotalFee());
        tabOrder.setVipGoodsId(tabVipGoods.getId());
        tabOrder.setOutTradeNo(generateOrderNumber());
        return tabOrder;
    }

    private String generateOrderNumber() {
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));
        UUID uuid = UUID.randomUUID();
        String randomPart = uuid.toString().substring(19, 23);
        return "ORD" + timestamp + randomPart;
    }


    public synchronized String payNotify(HttpServletRequest request) throws Exception {
        String signature = request.getHeader("Wechatpay-Signature");
        // 请求头Wechatpay-nonce
        String nonce = request.getHeader("Wechatpay-Nonce");
        // 请求头Wechatpay-Timestamp
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        // 微信支付证书序列号
        String serial = request.getHeader("Wechatpay-Serial");
        // 签名方式
        String signType = request.getHeader("Wechatpay-Signature-Type");

        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(signType)
                .body(getReqBody(request))
                .build();

        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if(Transaction.TradeStateEnum.SUCCESS ==transaction.getTradeState()){
            //商户订单号
            String outTradeNo = transaction.getOutTradeNo();
            //微信订单号
            String transactionId = transaction.getTransactionId();
            String successTime = transaction.getSuccessTime();
            LambdaQueryWrapper<TabOrder> lambda = Wrappers.<TabOrder>query().lambda();
            lambda.eq(TabOrder::getOutTradeNo,outTradeNo);
            TabOrder tabOrder = tabOrderMapper.selectOne(lambda);
            tabOrder.setPayStatus(1);
            tabOrder.setTransactionId(transactionId);
            tabOrder.setPayTime(DateUtil.parseDateTime(successTime));
            tabOrderMapper.updateById(tabOrder);
            Long vipGoodsId = tabOrder.getVipGoodsId();
            TabVipGoods tabVipGoods = tabVipGoodsMapper.selectById(vipGoodsId);
            String type = tabVipGoods.getType();

            String openId = tabOrder.getOpenId();
            LambdaQueryWrapper<SysUser> sysUserWrapper = Wrappers.<SysUser>query().lambda();
            sysUserWrapper.eq(SysUser::getOpenId,openId);
            SysUser user = sysUserMapper.selectOne(sysUserWrapper);
            user.setStatus("1");
            Date currentDate = new Date();
            user.setVipStartTime(currentDate);

            //更新会员时间
            if("1".equals(type)){

                DateTime endDate = DateUtil.offsetMonth(currentDate, 1);
                user.setVipEndTime(endDate);
            }else if("2".equals(type)){
                DateTime endDate = DateUtil.offsetMonth(currentDate,  3);
                user.setVipEndTime(endDate);
            }else if("3".equals(type)) {
                DateTime endDate = DateUtil.offsetMonth(currentDate,  12);
                user.setVipEndTime(endDate);
            }

            sysUserMapper.updateById(user);

            return JSONObject.toJSONString (R.ok(transaction));
        }else {
            R<Transaction> fail = R.fail(transaction, "支付失败");
            return JSONObject.toJSONString (fail);
        }

    }

    private String getReqBody(HttpServletRequest request) throws IOException {
        BufferedReader reader = request.getReader();
        StringBuilder requestBody = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null){
            requestBody.append(line);
        }
        return requestBody.toString();
    }

    /**
     * 根据商户订单号查询wx订单
     * @param req
     * @return
     */
    public R queryOrderByOrderNo(QueryOrderReq req) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wechatConfig.getMerchantId());
        queryRequest.setOutTradeNo(req.getOrderNo());
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder()
                        .config(rsaAutoCertificateConfig)
                        .signType("RSA") // 不填默认为RSA
                        .build();
        Transaction result = service.queryOrderByOutTradeNo(queryRequest);
        if(Transaction.TradeStateEnum.SUCCESS == result.getTradeState()){
            LinkedHashMap retmap = new LinkedHashMap();
            retmap.put("out_trade_no", result.getOutTradeNo());
            retmap.put("transaction_id", result.getTransactionId());
            retmap.put("success", true);
            retmap.put("msg", "支付成功！");
            retmap.put("success_time", DateUtil.parseDateTime((result.getSuccessTime())));
            return R.ok(retmap);
        }else {
            return R.fail("没有查询到相关订单");
        }

    }

    /**
     * 根据微信订单号查询
     * @param req
     * @return
     */
    public R queryOrderByPaymentNo(QueryOrderReq req) {
        QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
        queryRequest.setMchid(wechatConfig.getMerchantId());
        queryRequest.setTransactionId(req.getPaymentNo());
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder()
                        .config(rsaAutoCertificateConfig)
                        .signType("RSA") // 不填默认为RSA
                        .build();
        Transaction result = service.queryOrderById(queryRequest);
        if(Transaction.TradeStateEnum.SUCCESS == result.getTradeState()){
            LinkedHashMap retmap = new LinkedHashMap();
            retmap.put("out_trade_no", result.getOutTradeNo());
            retmap.put("transaction_id", result.getTransactionId());
            retmap.put("success", true);
            retmap.put("msg", "支付成功！");
            retmap.put("success_time", DateUtil.parseDateTime((result.getSuccessTime())));
            return R.ok(retmap);
        }else {
            return R.fail("没有查询到相关订单");
        }
    }

    /**
     *
     * @param outTradeNo
     * @param totalAmount
     * @return
     */
    public R createRefund(String outTradeNo, Long totalAmount) {
        LambdaQueryWrapper<TabOrder> lambda = Wrappers.<TabOrder>query().lambda();
        lambda.eq(TabOrder::getOutTradeNo,outTradeNo);
        TabOrder tabOrder = tabOrderMapper.selectOne(lambda);
        if(Objects.isNull(tabOrder)){
            return R.fail("订单不存在");
        }
        tabOrder.setPayStatus(2);
        tabOrderMapper.updateById(tabOrder);
        RefundService service = new RefundService.Builder()
                .config(rsaAutoCertificateConfig)
                .build();
        CreateRequest request = new CreateRequest();
        // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
        request.setOutTradeNo(outTradeNo);
        String outRefundNo = "REFUND_" + outTradeNo;
        request.setOutRefundNo(outRefundNo);

        AmountReq amount = new AmountReq();
        amount.setTotal(totalAmount);
        amount.setRefund(totalAmount);
        amount.setCurrency("CNY");

        request.setAmount(amount);
        request.setNotifyUrl(wechatConfig.getRefundNotifyUrl());
        //接收退款返回参数
        Refund refund = service.create(request);
        log.info("退款返回信息：{}", refund);
        if (refund.getStatus().equals(Status.SUCCESS)) {
            //更新用户信息
            String openId = tabOrder.getOpenId();
            LambdaQueryWrapper<SysUser> sysUserWrapper = Wrappers.<SysUser>query().lambda();
            sysUserWrapper.eq(SysUser::getOpenId,openId);
            SysUser user = sysUserMapper.selectOne(sysUserWrapper);
            user.setStatus("0");
            sysUserMapper.updateById(user);
            return R.ok("退款成功",refund.getOutRefundNo());
        }else {
            return R.fail("退款失败",JSONObject.toJSONString(refund));
        }

    }
}
